<template>
    <div
      ref="scrollContainer"
      class="scroll-container"
      :style="containerStyle"
      @mouseover="debouncedMouseOver"
      @mouseleave="debouncedMouseLeave"
      @wheel="handleMouseWheel"
      @touchstart="handleTouchStart"
      @touchmove="handleTouchMove"
      @touchend="handleTouchEnd"
    >
      <ul ref="scrollList" class="scroll-list" :style="scrollListStyle">
        <li v-for="(item, index) in displayItems" :key="index" :style="itemStyle">
          <slot :item="item" :index="index">
            {{ item }}
          </slot>
        </li>
      </ul>
    </div>
  </template>
   
  <script>
  export default {
    name: "AutoScroll",
    props: {
      items: { type: Array, required: true },
      stepTime: { type: Number, default: 1000 },
      stepHeight: { type: Number, default: 220 },
      stepWidth: { type: Number, default: 220 },
      threshold: { type: Number, default: 1 },
      containerHeight: { type: Number, default: 220 },
      containerWidth: { type: Number, default: 220 },
      horizontal: { type: Boolean, default: false },
      fadeInOut: { type: Boolean, default: false },
    },
    data() {
      return {
        intervalId: null,
        isHover: false,
        currentPosition: 0,
        animationDuration: 1000,
        alignTimeout: null,
        touchStartPosition: 0,
        showScrollbar: false,
      };
    },
    computed: {
      shouldScroll() {
        return this.items.length > this.threshold;
      },
      displayItems() {
        return this.items.length > this.threshold
          ? [...this.items, ...this.items]
          : this.items;
      },
      scrollListStyle() {
        return {
          transition: this.isHover
            ? "none"
            : `transform ${this.animationDuration}ms linear`,
          display: this.fadeInOut ? "flex" : "block",
          opacity: this.fadeInOut ? (this.isHover ? 1 : 0.5) : 1,
          flexDirection: this.horizontal ? "row" : "column",
        };
      },
      containerStyle() {
        return {
          height: this.horizontal ? "auto" : `${this.containerHeight}px`,
          width: this.horizontal ? `${this.containerWidth}px` : "auto",
          overflowY: this.showScrollbar ? "auto" : "hidden",
          overflowX: this.showScrollbar && this.horizontal ? "auto" : "hidden",
          position: "relative",
        };
      },
      itemStyle() {
        return {
          height: this.horizontal ? "auto" : `${this.stepHeight}px`,
          width: this.horizontal ? `${this.stepWidth}px` : "auto",
        };
      },
    },
    mounted() {
      this.initScrolling();
      document.addEventListener("visibilitychange", this.handleVisibilityChange);
    },
    beforeDestroy() {
      this.cleanUpScrolling();
      document.removeEventListener(
        "visibilitychange",
        this.handleVisibilityChange
      );
    },
    watch: {
      items() {
        this.initScrolling();
      },
    },
    methods: {
      handleVisibilityChange() {
        if (document.hidden) {
          this.stopScrolling();
        } else {
          this.startScrolling();
        }
      },
      debounce(fn, delay) {
        let timer;
        return function (...args) {
          clearTimeout(timer);
          timer = setTimeout(() => fn.apply(this, args), delay);
        };
      },
      initScrolling() {
        this.cleanUpScrolling();
        if (this.shouldScroll && !this.isHover) {
          this.startScrolling();
        }
      },
      startScrolling() {
        if (!this.intervalId) {
          this.intervalId = setInterval(this.scrollStep, this.stepTime);
        }
      },
      stopScrolling() {
        if (this.intervalId) {
          clearInterval(this.intervalId);
          this.intervalId = null;
        }
      },
      scrollStep() {
        const list = this.$refs.scrollList;
        const maxScrollPosition = this.horizontal
          ? list.scrollWidth / 2
          : list.scrollHeight / 2;
   
        if (this.currentPosition >= maxScrollPosition) {
          this.currentPosition = 0;
          list.style.transition = "none";
          this.updateTransform(list);
          setTimeout(() => {
            list.style.transition = `transform ${this.animationDuration}ms linear`;
            this.currentPosition += this.horizontal
              ? this.stepWidth
              : this.stepHeight;
            this.updateTransform(list);
          }, 50);
        } else {
          this.currentPosition += this.horizontal
            ? this.stepWidth
            : this.stepHeight;
          this.updateTransform(list);
        }
      },
      updateTransform(list) {
        if (this.horizontal) {
          list.style.transform = `translateX(-${this.currentPosition}px)`;
        } else {
          list.style.transform = `translateY(-${this.currentPosition}px)`;
        }
      },
      handleMouseOver() {
        this.isHover = true;
        this.showScrollbar = true;
        this.stopScrolling();
      },
      handleMouseLeave() {
        this.isHover = false;
        this.showScrollbar = false;
        if (this.shouldScroll) {
          this.alignToStep(); // 对齐到最近的步高或步宽
          this.startScrolling();
        }
      },
      handleMouseWheel(event) {
        const list = this.$refs.scrollList;
        const delta = event.deltaY || event.deltaX;
        this.currentPosition += delta;
   
        // 确保当前滚动位置在合理范围内
        if (this.currentPosition < 0) {
          this.currentPosition = 0;
        } else if (
          this.currentPosition >=
          (this.horizontal ? list.scrollWidth : list.scrollHeight) / 2
        ) {
          this.currentPosition =
            (this.horizontal ? list.scrollWidth : list.scrollHeight) / 2 - 1;
        }
   
        list.style.transition = "none";
        this.updateTransform(list);
      },
      handleTouchStart(event) {
        this.touchStartPosition = this.horizontal
          ? event.touches[0].clientX
          : event.touches[0].clientY;
        this.stopScrolling();
      },
      handleTouchMove(event) {
        const touchCurrentPosition = this.horizontal
          ? event.touches[0].clientX
          : event.touches[0].clientY;
        const delta = this.touchStartPosition - touchCurrentPosition;
        this.handleMouseWheel({ deltaY: delta, deltaX: delta });
        this.touchStartPosition = touchCurrentPosition;
      },
      handleTouchEnd() {
        if (this.shouldScroll) {
          this.alignToStep();
          this.startScrolling();
        }
      },
      alignToStep() {
        const list = this.$refs.scrollList;
        const stepSize = this.horizontal ? this.stepWidth : this.stepHeight;
   
        // 将当前位置调整到最近的完整项目位置
        this.currentPosition =
          Math.round(this.currentPosition / stepSize) * stepSize;
   
        list.style.transition = `transform ${this.animationDuration}ms linear`;
        this.updateTransform(list);
      },
      cleanUpScrolling() {
        this.stopScrolling();
        clearTimeout(this.alignTimeout);
      },
    },
    created() {
      this.debouncedMouseOver = this.debounce(this.handleMouseOver, 200);
      this.debouncedMouseLeave = this.debounce(this.handleMouseLeave, 200);
    },
  };
  </script>
   
  <style scoped>
  .scroll-container {
    overflow: hidden;
    position: relative;
    height: 100%;
    width: 100%;
  }
  .scroll-list {
    height: 100%;
    width: 100%;
    list-style-type: none;
    margin: 0;
    padding: 0;
    display: flex;
    flex-direction: column;
  }
  </style>